package com.yupi.springbootinit.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yupi.springbootinit.annotation.AuthCheck;
import com.yupi.springbootinit.bizmq.BiMessageProducer;
import com.yupi.springbootinit.common.BaseResponse;
import com.yupi.springbootinit.common.DeleteRequest;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.common.ResultUtils;
import com.yupi.springbootinit.constant.UserConstant;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.exception.ThrowUtils;
import com.yupi.springbootinit.manager.AiManager;
import com.yupi.springbootinit.model.dto.chart.*;
import com.yupi.springbootinit.model.entity.Chart;
import com.yupi.springbootinit.model.entity.User;
import com.yupi.springbootinit.model.enums.CharStatusEnum;
import com.yupi.springbootinit.model.vo.BiResponse;
import com.yupi.springbootinit.model.vo.ChartVO;
import com.yupi.springbootinit.service.ChartService;
import com.yupi.springbootinit.service.UserService;
import com.yupi.springbootinit.utils.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 帖子接口
 */
@RestController
@RequestMapping("/chart")
@Slf4j
public class ChartController {

    @Resource
    private ChartService chartService;

    @Resource
    private UserService userService;

    @Resource
    private AiManager aiManager;


    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @Resource
    private BiMessageProducer biMessageProducer;

    /**
     * 分页获取列表（封装类）
     *
     * @param chartQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<ChartVO>> listChartVOByPage(@RequestBody ChartQueryRequest chartQueryRequest,
                                                         HttpServletRequest request) {
        long current = chartQueryRequest.getCurrent();
        long size = chartQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        Page<Chart> postPage = chartService.page(new Page<>(current, size),
                chartService.getQueryWrapper(chartQueryRequest));
        return ResultUtils.success(chartService.getChartVOPage(postPage, request));
    }

    /**
     * 分页获取当前用户创建的资源列表
     *
     * @param chartQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<ChartVO>> listMyChartVOByPage(@RequestBody ChartQueryRequest chartQueryRequest,
                                                           HttpServletRequest request) {
        if (chartQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        chartQueryRequest.setUserId(loginUser.getId());
        long current = chartQueryRequest.getCurrent();
        long size = chartQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        Page<Chart> postPage = chartService.page(new Page<>(current, size),
                chartService.getQueryWrapper(chartQueryRequest));
        return ResultUtils.success(chartService.getChartVOPage(postPage, request));
    }

    /**
     * 智能分析
     *
     * @param multipartFile
     * @param genChartByAiRequest
     * @param request
     * @return
     */
    @PostMapping("/gen")
    public BaseResponse<BiResponse> genChartByAi(@RequestPart("file") MultipartFile multipartFile,
                                             GenChartByAiRequest genChartByAiRequest, HttpServletRequest request) {
        String name = genChartByAiRequest.getName();
        String goal = genChartByAiRequest.getGoal();
        String charType = genChartByAiRequest.getCharType();
        // 校验
        ThrowUtils.throwIf(StrUtil.isNotBlank(name) && name.length() > 100, ErrorCode.PARAMS_ERROR, "图表名称过长");
        ThrowUtils.throwIf(StrUtil.isBlank(goal), ErrorCode.PARAMS_ERROR, "分析目标为空");
        // 校验文件
        long fileSize = multipartFile.getSize();
        String originalFilename = multipartFile.getOriginalFilename();
        // 限制文件大小最大1M
        ThrowUtils.throwIf(fileSize > 1024 * 1024, ErrorCode.PARAMS_ERROR, "文件大小最大为1M");
        // 限制文件格式为xlsx
        String suffix = FileUtil.getSuffix(originalFilename);
        ThrowUtils.throwIf(!Arrays.asList("xlsx", "xls").contains(suffix), ErrorCode.PARAMS_ERROR, "文件类型只允许xlsx、xls");
        User loginUser = userService.getLoginUser(request);
        // 用户输入
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        String userGoal = goal + "，请使用" + charType;
        userInput.append(userGoal).append("\n");
        // 压缩后的数据
        String ssvData = ExcelUtils.excelToCsv(multipartFile);
        userInput.append("原始数据：").append(ssvData).append("\n");
        String doChat = aiManager.doChat(true, userInput.toString());
        String[] split = doChat.split("'【【【【【'");
        if (split.length < 3) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "AI 生成错误");
        }
        String genChart = split[1];
        String genResult = split[2];
        // 插入到数据库
        Chart chart = new Chart();
        chart.setChartName(name);
        chart.setGoal(goal);
        chart.setChartType(charType);
        chart.setChartData(ssvData);
        chart.setGenChart(genChart);
        chart.setGenResult(genResult);
        chart.setUserId(loginUser.getId());
        log.info("chart = {}", JSONUtil.toJsonStr(chart));
        boolean saveSuccess = chartService.save(chart);
        ThrowUtils.throwIf(!saveSuccess, ErrorCode.SYSTEM_ERROR, "图标保存失败");
        BiResponse result = new BiResponse(genChart, genResult);
        return ResultUtils.success(result);
    }

    /**
     * 智能分析（异步线程池）
     *
     * @param multipartFile
     * @param genChartByAiRequest
     * @param request
     * @return
     */
    @PostMapping("/gen/async")
    public BaseResponse<BiResponse> genChartByAiAsync(@RequestPart("file") MultipartFile multipartFile,
                                                 GenChartByAiRequest genChartByAiRequest, HttpServletRequest request) {
        String name = genChartByAiRequest.getName();
        String goal = genChartByAiRequest.getGoal();
        String charType = genChartByAiRequest.getCharType();
        // 校验
        ThrowUtils.throwIf(StrUtil.isNotBlank(name) && name.length() > 100, ErrorCode.PARAMS_ERROR, "图表名称过长");
        ThrowUtils.throwIf(StrUtil.isBlank(goal), ErrorCode.PARAMS_ERROR, "分析目标为空");
        // 校验文件
        long fileSize = multipartFile.getSize();
        String originalFilename = multipartFile.getOriginalFilename();
        // 限制文件大小最大1M
        ThrowUtils.throwIf(fileSize > 1024 * 1024, ErrorCode.PARAMS_ERROR, "文件大小最大为1M");
        // 限制文件格式为xlsx
        String suffix = FileUtil.getSuffix(originalFilename);
        ThrowUtils.throwIf(!Arrays.asList("xlsx", "xls").contains(suffix), ErrorCode.PARAMS_ERROR, "文件类型只允许xlsx、xls");
        User loginUser = userService.getLoginUser(request);
        // 用户输入
        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        String userGoal = goal + "，请使用" + charType;
        userInput.append(userGoal).append("\n");

        // 压缩后的数据
        String ssvData = ExcelUtils.excelToCsv(multipartFile);
        userInput.append("原始数据：").append(ssvData).append("\n");

        // 插入到数据库
        Chart chart = new Chart();
        chart.setChartName(name);
        chart.setGoal(goal);
        chart.setChartType(charType);
        chart.setChartData(ssvData);
        chart.setStatus(CharStatusEnum.WAIT.getValue());
        chart.setUserId(loginUser.getId());
        log.info("chart = {}", JSONUtil.toJsonStr(chart));
        boolean saveSuccess = chartService.save(chart);
        ThrowUtils.throwIf(!saveSuccess, ErrorCode.SYSTEM_ERROR, "图标保存失败");
        BiResponse result = new BiResponse();

        CompletableFuture.runAsync(() -> {
            // 先修改任务状态为执行中
            Chart updateChart = new Chart();
            updateChart.setId(chart.getId());
            updateChart.setStatus(CharStatusEnum.RUNNING.getValue());
            boolean updateSuccess = chartService.updateById(updateChart);
            if (!updateSuccess) {
                this.handleChartUpdateError(chart.getId(), "更新执行状态失败");
            }
            String doChat = aiManager.doChat(true, userInput.toString());
            String[] split = doChat.split("'【【【【【'");
            if (split.length < 3) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "AI 生成错误");
            }
            String genChart = split[1].trim();
            String genResult = split[2].trim();
            Chart updateChartResult = new Chart();
            updateChartResult.setId(chart.getId());
            updateChartResult.setGenChart(genChart);
            updateChartResult.setGenResult(genResult);
            updateChartResult.setStatus(CharStatusEnum.SUCCEED.getValue());
            boolean updateResultSuccess = chartService.updateById(updateChartResult);
            if (!updateResultSuccess) {
                this.handleChartUpdateError(chart.getId(), "更新图表结果失败");
            }
        }, threadPoolExecutor);

        return ResultUtils.success(result);
    }

    /**
     * 智能分析（异步消息队列）
     *
     * @param multipartFile
     * @param genChartByAiRequest
     * @param request
     * @return
     */
    @PostMapping("/gen/async/mq")
    public BaseResponse<BiResponse> genChartByAiAsyncMq(@RequestPart("file") MultipartFile multipartFile,
                                                      GenChartByAiRequest genChartByAiRequest, HttpServletRequest request) {
        String name = genChartByAiRequest.getName();
        String goal = genChartByAiRequest.getGoal();
        String charType = genChartByAiRequest.getCharType();
        // 校验
        ThrowUtils.throwIf(StrUtil.isNotBlank(name) && name.length() > 100, ErrorCode.PARAMS_ERROR, "图表名称过长");
        ThrowUtils.throwIf(StrUtil.isBlank(goal), ErrorCode.PARAMS_ERROR, "分析目标为空");
        // 校验文件
        long fileSize = multipartFile.getSize();
        String originalFilename = multipartFile.getOriginalFilename();
        // 限制文件大小最大1M
        ThrowUtils.throwIf(fileSize > 1024 * 1024, ErrorCode.PARAMS_ERROR, "文件大小最大为1M");
        // 限制文件格式为xlsx
        String suffix = FileUtil.getSuffix(originalFilename);
        ThrowUtils.throwIf(!Arrays.asList("xlsx", "xls").contains(suffix), ErrorCode.PARAMS_ERROR, "文件类型只允许xlsx、xls");
        User loginUser = userService.getLoginUser(request);
        // 压缩后的数据
        String ssvData = ExcelUtils.excelToCsv(multipartFile);
        // 插入到数据库
        Chart chart = new Chart();
        chart.setChartName(name);
        chart.setGoal(goal);
        chart.setChartType(charType);
        chart.setChartData(ssvData);
        chart.setStatus(CharStatusEnum.WAIT.getValue());
        chart.setUserId(loginUser.getId());
        log.info("chart = {}", JSONUtil.toJsonStr(chart));
        boolean saveSuccess = chartService.save(chart);
        ThrowUtils.throwIf(!saveSuccess, ErrorCode.SYSTEM_ERROR, "图标保存失败");
        BiResponse result = new BiResponse();
        Long chartId = chart.getId();
        biMessageProducer.sendMessage(String.valueOf(chartId));

        return ResultUtils.success(result);
    }

    private void handleChartUpdateError(Long chartId, String execMessage) {
        Chart updateChart = new Chart();
        updateChart.setId(chartId);
        updateChart.setStatus(CharStatusEnum.FAILED.getValue());
        updateChart.setExecMessage(execMessage);
        chartService.updateById(updateChart);
    }

}
